/*
 * Copyright (C) 2012 POAS.VSTU
 */
package ui;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import model.*;


/**
 * Игровая панель игры, в пределах которой идет игровой процесс и перемещаются карты
 * @author POAS
 */
public class UIGamePanel extends JPanel implements GameEventListener, GameProcessEventListener {

   // Размеры панели
    private static final int WIDTH = 983;
    private static final int HEIGHT = 700;

    // Фон
    private static final String BACKGROUND_IMAGE_FILE = "./src/images/frame/background.jpg";

    private static HashMap<String, Face> sFaceLabels = new HashMap<>();
    private static String[] sComboBoxItems;

    // Задержка между кадрами при движени карт; влияет на
    // скорость перемещения карт (но не на кол-во кадров)
    public static final int TIME_MOVE_STEP_MS = 2;

    /** Модель игры*/
    private GameModel           mModel;
    /** Отбой */
    private UICardPileRecycle   mCardPileRecycle;
    /** Кон */
    private UICardPileKitty     mCardPileKitty;
    /** Колода карт */
    private UICardStack         mCardStack;
    /** Карта, которая не раздается игрокам */
    private UICardPile          mExtraCardPile;

    /** Виджет выбора ранга */
    private JComboBox           mRank;

    // Игроки, начиная от игрока-человека по часовой стрелке
    private ArrayList<UIPlayer> mPlayers;

    // Карта соответствия между моделью карт (Card) и их представлением (UICard)
    private HashMap<Card, UICard> mModelToUICards;
    //Карта соответствия между моделью стопок карт (CardPile) и их представлением (UICardPile)
    private HashMap<CardPile, UICardPile> mModelToUICardPiles;

    private ActionScript movementScript = new ActionScript(this);

    static {
        sFaceLabels.put("Шестерка", Face.SIX);
        sFaceLabels.put("Семерка", Face.SEVEN);
        sFaceLabels.put("Восьмерка", Face.EIGHT);
        sFaceLabels.put("Девятка", Face.NINE);
        sFaceLabels.put("Десятка", Face.TEN);
        sFaceLabels.put("Валет", Face.JACK);
        sFaceLabels.put("Дама", Face.QUEEN);
        sFaceLabels.put("Король", Face.KING);
        sFaceLabels.put("Туз", Face.ACE);

        sComboBoxItems = new String[]{"Шестерка", "Семерка", "Восьмерка", "Девятка", "Десятка", "Валет", "Дама", "Король", "Туз"};
    }
    /**
     * Конструктр
     */
    public UIGamePanel() {
        this.setLayout(null);

        mModelToUICards = new HashMap<Card, UICard>();
        mModelToUICardPiles = new HashMap<CardPile, UICardPile>();

        mModel = new GameModel();
        mModel.addGameEventListener(this);
        mModel.addGameProcessEventListener(this);

        mCardPileRecycle = new UICardPileRecycle(mModel.getRecycle(), this);
        mCardPileRecycle.mModel.addGameEventListener(this);
        mModelToUICardPiles.put(mModel.getRecycle(), mCardPileRecycle);

        mCardPileKitty = new UICardPileKitty(mModel.getKitty(), this);
        mCardPileKitty.mModel.addGameEventListener(this);
        mCardPileKitty.setLocation(280, 310);
        mCardPileKitty.addGameProcessEventListener(this);
        mModelToUICardPiles.put(mModel.getKitty(), mCardPileKitty);

        // создание и настройка колоды
        mCardStack = new UICardStack(mModel.getStack(), this);
        mCardStack.mModel.addGameEventListener(this);
        mCardStack.setLocation(480, 310);
        mModelToUICardPiles.put(mModel.getStack(), mCardStack);

        mExtraCardPile = new UICardPile(mModel.getExtraCards(), this);
        mExtraCardPile.mModel.addGameEventListener(this);
        mExtraCardPile.setLocation(30, 480);
        mModelToUICardPiles.put(mModel.getExtraCards(), mExtraCardPile);


        // Создаем игроков
        mPlayers = new ArrayList<UIPlayer>();
        UIPlayer newPlayer;
        int numRotate = 0;
        for(Object player: mModel.getAllPlayers().toArray()) {
            if (player instanceof Gamer) {
                newPlayer = new UIGamer((Player)player, this);
            }
            else {
                newPlayer = new UIPlayer((Player)player, this);
            }
            mPlayers.add(newPlayer);
            newPlayer.rotate(numRotate);
            ((Player)player).getCards().addGameEventListener(this);
            ((Player)player).addGameProcessEventListener(mModel);
            mModelToUICardPiles.put(((Player)player).getCards(), newPlayer.getUICardPile());
            numRotate++;
        }

        // Добавить UIGamer и UICardPileKitty как слушателя событий всех карт.
        for (UICard card: mModelToUICards.values()) {
            card.addMouseListener(((UIGamer)mPlayers.get(0)));
            card.addMouseListener(mCardPileKitty);
        }

        // устанавливаем позиции игроков (пока что для пробы)
        Iterator iterUIPlayers = mPlayers.iterator();
        ((UIPlayer) iterUIPlayers.next()).setLocation(new Point(470, 570));
        ((UIPlayer) iterUIPlayers.next()).setLocation(new Point(140, 236));
        ((UIPlayer) iterUIPlayers.next()).setLocation(new Point(470, 20));
        ((UIPlayer) iterUIPlayers.next()).setLocation(new Point(858, 236));

        //настраиваем виджет выбора ранга
        mRank = new JComboBox(sComboBoxItems);
        mRank.setSize(100, 26);
        mRank.setLocation(getWidth() / 2 - mRank.getWidth() / 2, 220);
        mRank.addItemListener(((UIGamer) mPlayers.get(0)));
        add(mRank);
        setRankVisible(true);
        setRankEnabled(false);

        Thread tModel = new Thread(mModel);
        tModel.start();

        // добавляем фоновое изображение
        JLabel bgLabel = new javax.swing.JLabel();
        bgLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        bgLabel.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(102, 102, 102), 1, true));
        ImageIcon bgIcon = new ImageIcon(BACKGROUND_IMAGE_FILE);
        bgLabel.setIcon(bgIcon);
        bgLabel.setBounds(0, 0, getWidth(), getHeight());
        add(bgLabel);
    }

    /** Получить модель игры */
    public GameModel getModel() {
        return mModel;
    }

    /** Получить ширину игрового поля */
    @Override
    public int getWidth() {
        return WIDTH;
    }

    /** Получить высоту игрового поля */
    @Override
    public int getHeight() {
        return HEIGHT;
    }

    /** Создать UI карту */
    UICard createUICard(Card card) {
        if (mModelToUICards.containsKey(card)) {
            throw new UnsupportedOperationException("Попытка создание представления "
                    + "карты, совпадающей уже с имеющейся");
        }

        UICard uiCard = new UICard(card, this);
        mModelToUICards.put(card, uiCard);
        return uiCard;
    }

    /**
     * Получить UI-карту
     * @param card Карта из модели игры
     */
    public UICard getUICard(Card card) {
        if (!mModelToUICards.containsKey(card)) {
            throw new UnsupportedOperationException("Попытка получить несуществующую "
                    + "UI карту");
        }

        return mModelToUICards.get(card);
    }

    /**
     * Получить UI-стопку карту
     * @param cardPile Стопка карт из модели игры
     */
    public UICardPile getUICardPile(CardPile cardPile) {
        if (!mModelToUICardPiles.containsKey(cardPile)) {
            throw new UnsupportedOperationException("Попытка получить несуществующую "
                    + "UI стопку карт");
        }

        return mModelToUICardPiles.get(cardPile);
    }

    public JComboBox getRankComboBox() {
        return mRank;
    }


    /**
     * Управление возможностью воздействовать на игровое поле игроком
     * @param isEnabled - true, чтобы игроку были доступны все действия над игровым полем
     */
    private void enableUserActions(boolean isEnabled) {

    }

    void sleep() throws InterruptedException {
        sleep(TIME_MOVE_STEP_MS);
    }

    void sleep(int ms) throws InterruptedException {
        Thread.sleep(ms);
    }

    @Override
    public void cardsMoved(GameEvent e) {

        UICardPile uiCardPile = getUICardPile(e.getCardPileTo());

        // получаем перемещаемые карты
        ArrayList<UICard> listUIcards = new ArrayList();
        for(Card card: e.getCards()) {
            listUIcards.add(getUICard(card));
        }

        uiCardPile.dragIn(e.getCards());

    }

    @Override
    public void cardsExtracted(GameEvent e) {
        UICardPile uiCardPile = getUICardPile(e.getCardPileFrom());

        uiCardPile.pop(e.getCards());
    }

    @Override
    public void cardsAdded(GameEvent e) {
        //System.out.println("cardsAdded");
        //throw new UnsupportedOperationException("Not supported yet.");

        UICardPile uiCardPile = getUICardPile(e.getCardPileTo());

        uiCardPile.push(e.getCards());

        if (e.getCardPileTo() instanceof PlayerCardPile && mPlayers.get(0).getUICardPile().getModel() != e.getCardPileTo()) {
            for (UICard ui: uiCardPile.getUICards()) {
                ui.actionTurnFaceDown(0);
            }
        }
    }

    void addMovement(Action movement) {
        movementScript.addMovement(movement, 0);
    }

    void executeMovements() throws InterruptedException {
        movementScript.execute();
    }

    @Override
    public void userActionWaitStart() {
        try {
            movementScript.execute();
        } catch (InterruptedException ex) {
            Logger.getLogger(UIGamePanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void allCardsInStack() {
        movementScript.addSyncMoment();
    }

    @Override
    public void cardSelected(GameEvent e) {
        getUICardPile((CardPile) e.getSource()).select(getUICard(e.getSwitchedCard()));
    }

    @Override
    public void cardDeselected(GameEvent e) {
        getUICardPile((CardPile) e.getSource()).deselect(getUICard(e.getSwitchedCard()));
    }

    @Override
    public void playerMadeDecision(GameProcessEvent e) {

    }

    @Override
    public void playerTurnStarted(GameProcessEvent e) {
        //System.out.println("Игрок начал ход");
    }

    @Override
    public void playerTurnEnded(GameProcessEvent e) {
        //System.out.println("Игрок закончил ход");
    }

    @Override
    public void playerPassedTurn(GameProcessEvent e) {
        //System.out.println("Игрок " + e.getPlayer().getName() + " передает ход игроку " + e.getNextPlayer().getName());
    }

    @Override
    public void playerCheckedCard(GameProcessEvent e) {

        // Показать игроку карту
        mCardPileKitty.choose(getUICard(e.getCard()));

        // Выполнить действия по правилам игры
        mModel.playerCheckedCard(e);
    }

    @Override
    public void playerRoundEnded(GameProcessEvent e) {

    }

    /** Сделать виджет выбора ранга видимым
     * @param flag признак
     */
    public void setRankVisible(boolean flag){
        mRank.setVisible(flag);
        paintImmediately(mRank.getBounds());
    }

    /** Сделать виджет выбора ранга доступным
     * @param flag признак
     */
    public void setRankEnabled(boolean flag){
        mRank.setEnabled(flag);
        paintImmediately(mRank.getBounds());
    }

    /** Задать ранг (по рангу-элементу перечисления). */
    public void setRank(Face face){
        mRank.setSelectedItem(getFaceLabel(face));
        mModel.setRank(face);
        paintImmediately(mRank.getBounds());
    }

    /** Получить ранг по названию ранга. */
    public Face getFaceByLabel(String name) {
        return sFaceLabels.get(name);
    }

    public String getFaceLabel(Face face) {
        for( String s: sFaceLabels.keySet()) {
            if (sFaceLabels.get(s) == face)
                return s;
        }
        return "Шестерка";
    }
}